package com.hopes.bizz.close.position.support.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.hopes.bizz.close.basic.entity.ClosedGpsDeviceEntity;
import com.hopes.bizz.close.basic.service.ClosedGpsDeviceService;
import com.hopes.bizz.close.position.dto.HazardCachePositionDTO;
import com.hopes.bizz.close.position.entity.ClosedHazardCarPositionHisEntity;
import com.hopes.bizz.close.position.support.PositionTaskHandle;
import com.hopes.bizz.close.position.support.RedisHandleSupport;
import com.hopes.bizz.close.position.support.RedisRtPositionHandle;
import com.hopes.bizz.close.position.vo.HazardCachePositionVO;
import com.hopes.bizz.close.position.vo.SocketSendVO;
import com.hopes.bizz.close.visitor.entity.ClosedHazardCarApplyEntity;
import com.hopes.bizz.close.visitor.service.ClosedHazardCarApplyService;
import com.hopes.bizz.common.core.constant.CommonConstant;
import com.hopes.boss.common.core.constant.CommonConstants;
import com.hopes.boss.common.data.tenant.TenantBroker;
import com.hopes.boss.common.message.distribute.WebMessageBO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.TimerTask;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * @author yumr
 * @ProjectName bizz
 * @Description 危险品实时数据处理类
 * @time 2024/1/30 14:48
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RedisHazardRtPositionHandle implements RedisRtPositionHandle, InitializingBean, DisposableBean {

    public static final String CHANNEL = "hazard-position-channel";

    private final RedisHandleSupport redisHandleSupport;
    private final PositionTaskHandle positionTaskHandle;
    private final ClosedGpsDeviceService closedGpsDeviceService;
    private final ClosedHazardCarApplyService closedHazardCarApplyService;

    private ScheduledThreadPoolExecutor threadPoolExecutor;

    @Override
    public void afterPropertiesSet() throws Exception {
        final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("close-position-").build();
        threadPoolExecutor = new ScheduledThreadPoolExecutor(1, threadFactory);
        threadPoolExecutor.scheduleWithFixedDelay(new TimerTask() {
            @Override
            public void run() {
                TenantBroker.runAs(CommonConstants.TENANT_ID_1, (tenantId) -> {
                    // 1、处理实时定位数据
                    final boolean handleCacheRes = positionTaskHandle.handleCachePosition();
                    // 2、处理历史定位数据
                    final boolean handleQueueRes = positionTaskHandle.handleQueuePosition();
                    log.debug("定时任务处理实时定位数据结果：{}， 处理历史定位数据：{}", handleCacheRes, handleQueueRes);
                });
            }
        }, 5, 5, TimeUnit.SECONDS);

    }

    @Override
    public void destroy() throws Exception {
        threadPoolExecutor.shutdown();
    }

    @Override
    public void handleResolver(HazardCachePositionDTO hazardCachePositionDTO) {
        TenantBroker.runAs(CommonConstants.TENANT_ID_1, (tenantId) -> {
            // 1、查询GPS设备
            final List<ClosedGpsDeviceEntity> closedGpsDeviceList = closedGpsDeviceService.queryGpsDeviceList();
            if (CollUtil.isEmpty(closedGpsDeviceList)) {
                return;
            }
            final Optional<ClosedGpsDeviceEntity> gpsDeviceOptional = closedGpsDeviceList.stream().filter(e ->
                    StrUtil.isNotEmpty(e.getDeviceNo()) && e.getDeviceNo().equals(hazardCachePositionDTO.getDeviceNo())).findFirst();
            if (gpsDeviceOptional.isEmpty()) {
                return;
            }
            // 2、查询绑定了GPS设备的危险品车辆
            final List<ClosedHazardCarApplyEntity> hazardCarApplyList = closedHazardCarApplyService.queryBindGpsDeviceList();
            if (CollUtil.isEmpty(hazardCarApplyList)) {
                return;
            }
            final Optional<ClosedHazardCarApplyEntity> hazardCarApplyOptional = hazardCarApplyList.stream().filter(e ->
                    StrUtil.isNotEmpty(e.getGpsDeviceNo()) && e.getGpsDeviceNo().equals(hazardCachePositionDTO.getDeviceNo())).findFirst();
            if (hazardCarApplyOptional.isEmpty()) {
                return;
            }
            // 3、构建实时定位数据缓存对象
            final HazardCachePositionVO hazardCachePositionVo = redisHandleSupport.buildHazardCachePosition(hazardCachePositionDTO, gpsDeviceOptional.get(), hazardCarApplyOptional.get());
            // 4、ws发送实时数据
            final SocketSendVO<HazardCachePositionVO> socketSendVO = new SocketSendVO<>(hazardCachePositionVo);
            final WebMessageBO webMessageBO = WebMessageBO.broadcastMessage(CommonConstants.TENANT_ID_1.toString(), JSON.toJSONString(socketSendVO));
            redisHandleSupport.messageSend(Collections.singletonList(webMessageBO));

            // 5、定位历史数据入队列
            try {
                final ClosedHazardCarPositionHisEntity hisPosition = buildHisHazardCarPosition(hazardCarApplyOptional, hazardCachePositionVo);
                final boolean offerRes = positionTaskHandle.offerQueuePosition(hisPosition);
                log.debug("GPS设备编码:{} 定位数据入队列结果：{}", hisPosition.getDeviceNo(), offerRes);
            }catch (Exception e) {
                log.error("GPS设备编码:{} 定位数据入队列异常！", hazardCachePositionVo.getDeviceNo(), e);
            }
        });
    }

    /**
     * 构建危险品车辆历史定位数据
     * @param hazardCachePositionVo  vo
     * @return                       结果集
     */
    private ClosedHazardCarPositionHisEntity buildHisHazardCarPosition(Optional<ClosedHazardCarApplyEntity> hazardCarApplyOptional, HazardCachePositionVO hazardCachePositionVo) {
        final ClosedHazardCarPositionHisEntity hisPosition = new ClosedHazardCarPositionHisEntity();
        BeanUtils.copyProperties(hazardCachePositionVo, hisPosition);
        hisPosition.setHazardApplyId(hazardCarApplyOptional.map(ClosedHazardCarApplyEntity::getId).orElse(null));
        hisPosition.setHazardApplyBillNo(hazardCarApplyOptional.map(ClosedHazardCarApplyEntity::getBillNo).orElse(null));
        hisPosition.setSpeed(Optional.of(hazardCachePositionVo).map(HazardCachePositionVO::getSpeed).map(String::valueOf).orElse(null));
        hisPosition.setInRoadFlag(ObjUtil.isNotNull(hazardCachePositionVo.getInRoadFlag()) && hazardCachePositionVo.getInRoadFlag() ? CommonConstant.boolean_true_string : CommonConstant.boolean_false_string);
        hisPosition.setInCompanyFlag(ObjUtil.isNotNull(hazardCachePositionVo.getInCompanyFlag()) && hazardCachePositionVo.getInCompanyFlag() ? CommonConstant.boolean_true_string : CommonConstant.boolean_false_string);
        hisPosition.setInParkingLotFlag(ObjUtil.isNotNull(hazardCachePositionVo.getInParkingLotFlag()) && hazardCachePositionVo.getInParkingLotFlag() ? CommonConstant.boolean_true_string : CommonConstant.boolean_false_string);
        return hisPosition;
    }

    @Override
    public String channel() {
        return RedisHazardRtPositionHandle.CHANNEL;
    }

    @Override
    public Class<HazardCachePositionDTO> messageClass() {
        return HazardCachePositionDTO.class;
    }




}
